/**
 * Copyright 2021 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef EXECUTE_GRAPH_ATTR_STORE_H
#define EXECUTE_GRAPH_ATTR_STORE_H
#include "any_value.h"
#include "definitions.h"
#include <functional>
#include <string>
#include <unordered_map>
namespace ge {
using AttrId = uint64_t;
enum AttrType {
  kAttrPredefinedInIr,  // IR预定义的属性
  kAttrGeneral,         // 通用属性
  kAttrTypeEnd
};
constexpr inline uint32_t GetAttrType(AttrId id) {
  return id >> 32;
}
constexpr inline uint32_t GetSubAttrId(AttrId id) {
  return id & 0xffffffff;
}
constexpr inline AttrId GetAttrId(uint32_t type, uint32_t sub_id) {
  return static_cast<uint64_t>(type) << 32 | static_cast<uint64_t>(sub_id);
}
constexpr AttrId kInvalidAttrId = GetAttrId(0xffffffff, 0);

class AttrStore {
 public:
  AttrId GetIdByName(const char *name) const;
  void SetNameAndId(const char *name, AttrId id);

  template<typename T>
  bool Set(AttrId attr_id, const T &value) {
    auto v = GetOrCreate(attr_id);
    if (v == nullptr) {
      return false;
    }
    *v = value;
    return true;
  }
  template<typename T>
  bool Set(AttrId attr_id, T &&value) {
    auto v = GetOrCreate(attr_id);
    if (v == nullptr) {
      return false;
    }
    *v = std::forward<T>(value);
    return true;
  }

  template<typename T>
  bool Get(AttrId attr_id, T &value) const {
    auto v = GetAnyValue(attr_id);
    if (v == nullptr) {
      return false;
    }
    value = v->Get<T>();
    return true;
  }
  template<typename T>
  T *MutableGet(AttrId attr_id) {
    auto v = MutableAnyValue(attr_id);
    if (v == nullptr) {
      return nullptr;
    }
    return v->MutableGet<T>();
  }

 private:
  AnyValue *MutableAnyValue(AttrId attr_id);
  AnyValue *GetOrCreate(AttrId attr_id);
  const AnyValue *GetAnyValue(AttrId attr_id) const;
 private:
  using AttrSubId = uint32_t;
  std::unordered_map<std::string, AttrId> names_to_id_;
  std::array<std::unordered_map<AttrSubId, AnyValue>, kAttrTypeEnd> attrs_;
};
}

#endif  //EXECUTE_GRAPH_ATTR_STORE_H
